home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / sort.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  31KB  |  1,170 lines

  1. /* sort - sort a file of lines        Author: Michiel Huisjes */
  2.  
  3. /* SYNOPSIS:
  4.  *     sort [-funbirdcmt'x'] [+beg_pos[opts] [-end_pos]] [-o outfile] [file]..
  5.  *
  6.  *     [opts] can be any of
  7.  *     -f : Fold upper case to lower.
  8.  *     -n : Sort to numeric value (optional decimal point) implies -b
  9.  *     -b : Skip leading blanks
  10.  *     -i : Ignore chars outside ASCII range (040 - 0176)
  11.  *     -r : Reverse the sense of comparisons.
  12.  *     -d : Sort to dictionary order. Only letters, digits, comma's and points
  13.  *          are compared.
  14.  *     If any of these flags are used in [opts], then they override all global
  15.  *     ordering for this field.
  16.  *
  17.  *     I/O control flags are:
  18.  *     -u : Print uniq lines only once.
  19.  *     -c : Check if files are sorted in order.
  20.  *     -m : Merge already sorted files.
  21.  *     -o outfile : Name of output file. (Can be one of the input files).
  22.  *              Default is stdout.
  23.  *     - : Take stdin as input.
  24.  *
  25.  *     Fields:
  26.  *     -t'x' : Field separating character is 'x'
  27.  *     +a.b : Start comparing at field 'a' with offset 'b'. A missing 'b' is
  28.  *            taken to be 0.
  29.  *     -a.b : Stop comparing at field 'a' with offset 'b'. A missing 'b' is
  30.  *            taken to be 0.
  31.  *     A missing -a.b means the rest of the line.
  32.  */
  33.  
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #include <fcntl.h>
  37. #include <signal.h>
  38. #include <unistd.h>
  39.  
  40. #define OPEN_FILES    16    /* Nr of open files per process */
  41.  
  42. #define MEMORY_SIZE    (20 * 1024)    /* Total mem_size */
  43. #define LINE_SIZE    (1024 >> 1)    /* Max length of a line */
  44. #define IO_SIZE        (2 * 1024)    /* Size of buffered output */
  45. #define STD_OUT         1    /* Fd of terminal */
  46.  
  47. /* Return status of functions */
  48. #define OK         0
  49. #define ERROR        -1
  50. #define NIL_PTR        ((char *) 0)
  51.  
  52. /* Compare return values */
  53. #define LOWER        -1
  54. #define SAME         0
  55. #define HIGHER         1
  56.  
  57. /* Table definitions. */
  58. #define DICT        0x001    /* Alpha, numeric, letters and . */
  59. #define ASCII        0x002    /* All between ' ' and '~' */
  60. #define BLANK        0x004    /* ' ' and '\t' */
  61. #define DIGIT        0x008    /* 0-9 */
  62. #define UPPER        0x010    /* A-Z */
  63.  
  64. typedef int BOOL;
  65.  
  66. #define    FALSE    0
  67. #define    TRUE    1
  68.  
  69. typedef struct {
  70.   int fd;            /* Fd of file */
  71.   char *buffer;            /* Buffer for reads */
  72.   int read_chars;        /* Nr of chars actually read in buffer */
  73.   int cnt;            /* Nr of chars taken out of buffer */
  74.   char *line;            /* Contains line currently used */
  75. } MERGE;
  76.  
  77. #define NIL_MERGE    ((MERGE *) 0)
  78. MERGE merge_f[OPEN_FILES];    /* Merge structs */
  79. int buf_size;            /* Size of core available for each struct */
  80.  
  81. #define FIELDS_LIMIT    10    /* 1 global + 9 user */
  82. #define GLOBAL         0
  83.  
  84. typedef struct {
  85.   int beg_field, beg_pos;    /* Begin field + offset */
  86.   int end_field, end_pos;    /* End field + offset. ERROR == EOLN */
  87.   BOOL reverse;            /* TRUE if rev. flag set on this field */
  88.   BOOL blanks;
  89.   BOOL dictionary;
  90.   BOOL fold_case;
  91.   BOOL ascii;
  92.   BOOL numeric;
  93. } FIELD;
  94.  
  95. /* Field declarations. A total of FILEDS_LIMIT is allowed */
  96. FIELD fields[FIELDS_LIMIT];
  97. int field_cnt;            /* Nr of field actually assigned */
  98.  
  99. /* Various output control flags */
  100. BOOL check = FALSE;
  101. BOOL only_merge = FALSE;
  102. BOOL uniq = FALSE;
  103.  
  104. char *mem_top;            /* Mem_top points to lowest pos of memory. */
  105. char *cur_pos;            /* First free position in mem */
  106. char **line_table;        /* Pointer to the internal line table */
  107. BOOL in_core = TRUE;        /* Set if input cannot all be sorted in core */
  108.  
  109.  /* Place where temp_files should be made */
  110. char temp_files[] = "/tmp/sort.XXXXX.XX";
  111. char *output_file;        /* Name of output file */
  112. int out_fd;            /* Fd to output file (could be STD_OUT) */
  113. char out_buffer[IO_SIZE];    /* For buffered output */
  114.  
  115. char **argptr;            /* Pointer to argv structure */
  116. int args_offset;        /* Nr of args spilled on options */
  117. int args_limit;            /* Nr of args given */
  118.  
  119. char separator;            /* Char that separates fields */
  120. int nr_of_files = 0;        /* Nr_of_files to be merged */
  121. int disabled;            /* Nr of files done */
  122.  
  123. char USAGE[] = "Usage: sort [-funbirdcmt'x'] [+beg_pos [-end_pos]] [-o outfile] [file] ..";
  124.  
  125. /* Forward declarations */
  126. void catch();
  127. char *file_name(), *skip_fields();
  128. MERGE *skip_lines(), *print();
  129. extern char *msbrk(), *mbrk();
  130.  
  131. /* Table of all chars. 0 means no special meaning. */
  132. char table[256] = {
  133. /* '^@' to space */
  134.        0, 0, 0, 0, 0, 0, 0, 0,
  135.        0, BLANK | DICT, 0, 0, 0, 0, 0, 0,
  136.        0, 0, 0, 0, 0, 0, 0, 0,
  137.        0, 0, 0, 0, 0, 0, 0, 0,
  138.  
  139. /* Space to '0' */
  140.        BLANK | DICT | ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,
  141.        ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,
  142.        ASCII, ASCII,
  143.  
  144. /* '0' until '9' */
  145.      DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII,
  146.      DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII,
  147.      DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII,
  148.        DIGIT | DICT | ASCII,
  149.  
  150. /* ASCII from ':' to '@' */
  151.        ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,
  152.  
  153. /* Upper case letters 'A' to 'Z' */
  154.      UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  155.      UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  156.      UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  157.      UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  158.      UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  159.      UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  160.      UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  161.      UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  162.        UPPER | DICT | ASCII, UPPER | DICT | ASCII,
  163.  
  164. /* ASCII from '[' to '`' */
  165.        ASCII, ASCII, ASCII, ASCII, ASCII, ASCII,
  166.  
  167. /* Lower case letters from 'a' to 'z' */
  168.        DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII,
  169.        DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII,
  170.        DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII,
  171.        DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII,
  172.        DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII,
  173.        DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII,
  174.        DICT | ASCII, DICT | ASCII,
  175.  
  176. /* ASCII from '{' to '~' */
  177.        ASCII, ASCII, ASCII, ASCII,
  178.  
  179. /* Stuff from -1 to -177 */
  180.        0, 0, 0, 0, 0, 0, 0, 0, 0,
  181.        0, 0, 0, 0, 0, 0, 0, 0, 0,
  182.        0, 0, 0, 0, 0, 0, 0, 0, 0,
  183.        0, 0, 0, 0, 0, 0, 0, 0, 0,
  184.        0, 0, 0, 0, 0, 0, 0, 0, 0,
  185.        0, 0, 0, 0, 0, 0, 0, 0, 0,
  186.        0, 0, 0, 0, 0, 0, 0, 0, 0,
  187.        0, 0, 0, 0, 0, 0, 0, 0, 0,
  188.        0, 0, 0, 0, 0, 0, 0
  189. };
  190.  
  191. /*
  192.  * Get_opts () assigns the options into the field structure as described in ptr.
  193.  * This field structure could be the GLOBAL one.
  194.  */
  195. get_opts(ptr, field)
  196. register char *ptr;
  197. register FIELD *field;
  198. {
  199.   switch (*ptr) {
  200.       case 'b':            /* Skip leading blanks */
  201.     field->blanks = TRUE;
  202.     break;
  203.       case 'd':            /* Dictionary order */
  204.     field->dictionary = TRUE;
  205.     break;
  206.       case 'f':            /* Fold upper case to lower */
  207.     field->fold_case = TRUE;
  208.     break;
  209.       case 'i':            /* Skip chars outside ' ' '~' */
  210.     field->ascii = TRUE;
  211.     break;
  212.       case 'n':            /* Sort on numeric */
  213.     field->numeric = TRUE;
  214.     field->blanks = TRUE;
  215.     break;
  216.       case 'r':            /* Reverse comparisons */
  217.     field->reverse = TRUE;
  218.     break;
  219.       default:            /* Illegal options */
  220.     error(TRUE, USAGE, NIL_PTR);
  221.   }
  222. }
  223.  
  224. /* Atoi() converts a string to an int. */
  225. atoi(ptr)
  226. register char *ptr;
  227. {
  228.   register int num = 0;        /* Accumulator */
  229.  
  230.   while (table[*ptr] & DIGIT) num = num * 10 + *ptr++ - '0';
  231.  
  232.   return num;
  233. }
  234.  
  235. /* New_field () assigns a new field as described by the arguments.
  236.  * A field description is of the form: +a.b[opts] -c.d, where b and d, as well
  237.  * as -c.d and [opts] are optional. Nr before digit is field nr. Nr after digit
  238.  * is offset from field.
  239.  */
  240. new_field(field, offset, beg_fl)
  241. register FIELD *field;        /* Field to assign */
  242. int *offset;            /* Offset in argv structure */
  243. BOOL beg_fl;            /* Assign beg or end of field */
  244. {
  245.   register char *ptr;
  246.  
  247.   ptr = argptr[*offset];
  248.   *offset += 1;            /* Incr offset to next arg */
  249.   ptr++;
  250.  
  251.   if (beg_fl)
  252.     field->beg_field = atoi(ptr);    /* Assign int of first field */
  253.   else
  254.     field->end_field = atoi(ptr);
  255.  
  256.   while (table[*ptr] & DIGIT)    /* Skip all digits */
  257.     ptr++;
  258.  
  259.   if (*ptr == '.') {        /* Check for offset */
  260.     ptr++;
  261.     if (beg_fl)
  262.         field->beg_pos = atoi(ptr);
  263.     else
  264.         field->end_pos = atoi(ptr);
  265.     while (table[*ptr] & DIGIT)    /* Skip digits */
  266.         ptr++;
  267.   }
  268.   if (beg_